#ifndef DDC_SPRITE_H_INCLUDED
#define DDC_SPRITE_H_INCLUDED

#include <string>

#include "SDL.h"

#include "ddc_obj.h"
#include "ddc_text.h"
#include "ddc_texture.h"

/**
 * using SDL_RendererFlip, see SDL_render.h
 */
namespace DDC_SpriteFlip {
    typedef enum {
        FLIP_NONE = SDL_FLIP_NONE,
        FLIP_HORIZONTAL = SDL_FLIP_HORIZONTAL,
        FLIP_VERTICAL = SDL_FLIP_VERTICAL,
    } DDC_SpriteFlipEnum;
};

typedef struct {
    bool keepTextureScale = 0;
    DDC_Rect spriteRect;

    DDC_Point2D rotationCenter;
    double rotationAngle = 0;

    DDC_SpriteFlip::DDC_SpriteFlipEnum flip = DDC_SpriteFlip::FLIP_NONE;
} DDC_SpriteRenderContext;

class DDC_SpriteTexture {
public:
    DDC_Rect cutRect;
    DDC_BaseSDLTexture *texture;

    static DDC_SpriteTexture *
        CutFromBaseTexture(DDC_BaseSDLTexture *baseTexture, DDC_Rect *curRect);

    static DDC_SpriteTexture *
        CutFromBaseTexture(DDC_BaseSDLTexture *baseTexture, DDC_Rect curRect);

    void GetSize(int *w, int *h) {
        SDL_QueryTexture(texture->baseTexture, nullptr, nullptr, w, h);
    }

    void SetGameObjectSizeAsTextureSize(DDC_GameObject *go) {
        int w, h;
        this->GetSize(&w, &h);
        go->gameObjectRect.width = w;
        go->gameObjectRect.height = h;
    }
};

/*
class DDC_TextSpriteTexture: public DDC_SpriteTexture {
    DDC_BaseSDLTexture *_baseTextTexture;

public:
    DDC_TextSpriteTexture()
        :_text("", 10) {}

    int UseFontFile(const char *fontFileName);
};
*/

class DDC_SpriteRenderer {
protected:
    SDL_Renderer *renderer = nullptr;
    int _RenderSubmit(DDC_SpriteTexture *texture,
                      DDC_SpriteRenderContext *ctx);
public:
    bool __FixedOnScreen = false;

    void __SetRenderer(SDL_Renderer *renderer);
    virtual void Render(DDC_SpriteRenderContext *ctx) = 0;
};

class DDC_StaticSpriteRenderer: public DDC_SpriteRenderer {
public:
    DDC_SpriteTexture *spriteTexture = nullptr;
    void SetSpriteTexture(DDC_SpriteTexture *texture);

    virtual void Render(DDC_SpriteRenderContext *ctx);
};

class DDC_SpriteAnimate {
    std::vector<DDC_SpriteTexture*> _frames;
    int frameIndex = 0;
    bool loop = 0;
    int frameIntervalMS = 16;
    int timeAxis = 0;
    bool stop = 0;

public:
    void Replay() {
        frameIndex = 0;
        timeAxis = 0;
        stop = 0;
    }

    void Stop() {
        stop = 1;
    }

    void Resume() {
        stop = 0;
    }

    DDC_SpriteAnimate(int frameIntervalMS, bool loop) {
        this->frameIntervalMS = frameIntervalMS;
        this->loop = loop;
    }

    void AddFrame(DDC_SpriteTexture *texture) {
        _frames.push_back(texture);
    }

    void SetFrames(std::vector<DDC_SpriteTexture*> _frames) {
        this->_frames.clear();
        this->_frames = _frames;
    }

    DDC_SpriteTexture *GetFrame();
};

class DDC_AnimateSpriteRenderer: public DDC_SpriteRenderer {
    std::vector<DDC_SpriteAnimate *> _animates;
    int _currentState = 0;

public:
    void AddAnimate(DDC_SpriteAnimate *anim, int *outState) {
        *outState = _animates.size();
        _animates.push_back(anim);
    }

    virtual void Render(DDC_SpriteRenderContext *ctx);

    static int SetState(DDC_GameObject* go, int state);
    static int ReplayGameObject(DDC_GameObject *go, int state = -1);
    static int StopGameObject(DDC_GameObject *go, int state = -1);
    static int ResumeGameObject(DDC_GameObject *go, int state = -1);
};

#endif // DDC_SPRITE_H_INCLUDED
